package com.zk.config.web.util;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.zookeeper.KeeperException.NoAuthException;
import org.apache.zookeeper.ZooKeeper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.google.gson.Gson;
import com.zk.config.api.util.ZkCom;
import com.zk.config.api.util.ZkOperate;
import com.zk.config.web.constants.Constants;
import com.zk.config.web.model.NoAuthPerms;
import com.zk.config.web.model.Response;
import com.zk.config.web.model.TreeData;
import com.zk.config.web.model.TreeZkData;
import com.zk.config.web.model.ZkPerms;
import com.zk.config.web.op.MyZkClient;

public class ComUtil {
	
	private static final Logger log = LoggerFactory.getLogger(ComUtil.class);
	
	public static String toStr(String str) {
	    return str != null?str:"";
	}
	
	public static String getCxnstr() {
		HttpServletRequest req = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
		return (String) req.getSession().getAttribute(Constants.CX_STR);
	}
	
	public static String getRealPath(MyZkClient client, String path) {
		String realPath = "/";
		if(client == null || client.getZooKeeper() == null || "/".equals(path)) {
			return realPath;
		}
		ZooKeeper zk = client.getZooKeeper();
		if(client.useCache && client.zkData.size() > 0) {
			if(client.zkData.containsKey(path)) {
				realPath = path;
			} else {
				int index = path.lastIndexOf("/");
				String parent = ZkCom.getZkPath(path.substring(0, index));
				realPath =  getRealPath(client, parent);
			}
		} else {
			if(ZkOperate.existsNode(zk, path) != null) {
				realPath = path;
			} else {
				int index = path.lastIndexOf("/");
				String parent = ZkCom.getZkPath(path.substring(0, index));
				realPath =  getRealPath(client, parent);
			}
		}
		
		return realPath;
	}
	
	public static boolean parseBoolean(String str){
	    if(StringUtils.isNotEmpty(str)) {
	           try {
	               return Boolean.parseBoolean(str);
	        } catch (Exception e) {
	        }
	       }
	    return false;
	}
	
	public static List<TreeData> getZkNodes(List<TreeData> zkNodes, List<TreeData> srcZkNodes, String path, String checkPath) {
		if(srcZkNodes != null) {
			for(TreeData st:srcZkNodes) {
				String cpath = path != null && !"/".equals(path)?(ZkCom.getZkPath(path)+"/"+st.getText()):ZkCom.getZkPath(st.getText());
				TreeData td = new TreeData();
				td.setText(st.getText());
				List<TreeData> ctdList = new ArrayList<>();
				getZkNodes(ctdList, st.getChildren(), cpath, checkPath);
				if(ctdList.size() == 0) {
					td.setIcon("file");
					if(ZkCom.checkPath(checkPath,cpath) || "/".equals(cpath)) {
						Map<String, String> state = new HashMap<>();
						state.put("selected", "true");
						td.setState(state);
					}
				} else {
					if(ZkCom.checkPath(checkPath,cpath) || "/".equals(cpath)) {
						Map<String, String> state = new HashMap<>();
						state.put("opened", "true");
						td.setState(state);
					}
				}
				td.setChildren(ctdList);
				zkNodes.add(td);
			}
		}
		return zkNodes;
	}
	
	public static void getChildren(MyZkClient client, String path, List<TreeData> tdList, String checkPath, boolean watch){
		if(client == null || client.getZooKeeper() == null) return;
		try {
			ZooKeeper reader = client.getZooKeeper();
			if(reader.exists(path, watch) != null) {
				List<String> children = reader.getChildren(path, watch);
				if (CollectionUtils.isNotEmpty(children)) {
//					Collections.sort(children);
				} else {
					return;
				}
				
				for(String c:children) {
					String cpath = path != null && !"/".equals(path)?(ZkCom.getZkPath(path)+"/"+c):ZkCom.getZkPath(c);
					TreeData td = new TreeData();
					td.setText(c);
					List<TreeData> ctdList = new ArrayList<>();
					
					getChildren(client, cpath, ctdList, checkPath, watch);
					if(ctdList.size() == 0) {
						td.setIcon("file");
						if(ZkCom.checkPath(checkPath,cpath)) {
							Map<String, String> state = new HashMap<>();
							state.put("selected", "true");
							td.setState(state);
						}
					} else {
						if(ZkCom.checkPath(checkPath,cpath)) {
							Map<String, String> state = new HashMap<>();
							state.put("opened", "true");
							td.setState(state);
						}
					}
					td.setChildren(ctdList);
					tdList.add(td);
					if(client.useCache && !client.zkData.containsKey(cpath)) client.zkData.put(cpath, td);
				}
			}
		} catch (NoAuthException e) {
			log.warn(e.getMessage());
		} catch (Exception e) {
			e.printStackTrace();
			log.error(e.getMessage());
		}
	}
	
	public static Properties getChildren(ZooKeeper reader, String path, TreeZkData td, String key, StringBuilder keyInPath
	                                     , List<NoAuthPerms> noAuthPathList){
        try {
            boolean keyExists = StringUtils.isEmpty(key)?false:true;
            if(reader.exists(path, false) != null) {
                td.setName("/".equals(path)?"/":(path.substring(path.lastIndexOf("/")+1)));
                byte[] bytes = reader.getData(path, false, null);
                String data = bytes!=null?new String(bytes, Constants.defualtCharset):"";
                td.setData(data);
                if(keyExists && StringUtils.isNotEmpty(data)) {
                    Properties p = new Properties();
                    try {
                        p.load(new ByteArrayInputStream(data.getBytes(Constants.defualtCharset)));
                    } catch (IOException e) {
                        e.printStackTrace();
                        log.error("It isnt a valid properties file format.");
                    }
                    if(p.containsKey(key)) {
                        keyInPath.append(path);
                        return p;
                    }
                }
                List<String> children = reader.getChildren(path, false);
                if (CollectionUtils.isEmpty(children)) {
                    return null;
                }
                List<TreeZkData> tdList = new ArrayList<>();
                td.setChildren(tdList);
                for(String c:children) {
                    String cpath = path != null && !"/".equals(path)?(ZkCom.getZkPath(path)+"/"+c):ZkCom.getZkPath(c);
                    TreeZkData ctd = new TreeZkData();
                    Properties p = getChildren(reader, cpath, ctd, key, keyInPath, noAuthPathList);
                    if(p != null) return p;
                    tdList.add(ctd);
                }
            }
        } catch (NoAuthException e) {
            log.warn(e.getMessage());
            if(noAuthPathList != null) {
            	List<ZkPerms> permsList = Permiss.getPerms(reader, path);
            	if(permsList != null && permsList.size() > 0) {
            		NoAuthPerms noAuthPerms = new NoAuthPerms();
            		noAuthPerms.setPath(path);
            		noAuthPerms.setUserPerms(permsList);
                	noAuthPathList.add(noAuthPerms);
            	}
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error(e.getMessage());
        }
        return null;
    }
	
	public static void writeResponse(HttpServletResponse response, Response res) {
	    Gson gson = new Gson();
        response.setContentType("application/json;charset=UTF-8");
        try {
            response.getWriter().print(gson.toJson(res));
        } catch (IOException e) {
            e.printStackTrace();
            log.error(e.getMessage());
        }
    }
}
